package top.jojoace.CustomAnnotation.myAspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.Response;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Stream;

@Slf4j
@Aspect
@Component
public class MyAnnotationAspect {

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("@annotation(top.jojoace.CustomAnnotation.myAnnotation.MyAnnotation)")
    public void annoationPoint(){
    }

    // 第一个*代表返回类型不限
    // 第二个*代表所有类
    // 第三个*代表所有方法
    // (..) 代表参数不限
    @Pointcut("execution(public * top.jojoace.CustomAnnot不ation.todo.*.*(..))")
    public void pointCut(){};

    @Before(value = "annoationPoint() || pointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("方法执行前执行......before");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("<=====================================================");
        log.info("请求来源： =》" + request.getRemoteAddr());
        log.info("请求URL：" + request.getRequestURL().toString());
        log.info("请求方式：" + request.getMethod());
        log.info("响应方法：" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("请求参数：" + Arrays.toString(joinPoint.getArgs()));
        log.info("------------------------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 定义需要匹配的切点表达式，同时需要匹配参数.
     *  只有使用ProceedingJoinPoint，才能通过proceed(Object[])方法改变入参的值
     * @param pjp
     * @param arg
     * @return
     * @throws Throwable
     */
    @Around("annoationPoint() && args(arg)")
    public Object around(ProceedingJoinPoint pjp, String arg) throws Throwable{
        System.out.println("name:" + arg);
        System.out.println("方法环绕start...around");
        Object proceeded =null;
        try{
            Object[] args = pjp.getArgs();
            args[0] = args[0]+"修改ed";
            proceeded = pjp.proceed(args);
            System.out.println(proceeded.toString() + "----around");
        }catch (Throwable e){
            e.printStackTrace();
        }
        System.out.println("方法环绕end...around");
        return proceeded;
    }

    @After("within(top.jojoace.CustomAnnotation.todo.Do*)")
    public void after(){
        System.out.println("方法之后执行...after.");
    }

    @AfterReturning(pointcut="annoationPoint()",returning = "rst")
    public void afterRunning(Response rst){
        if(startTime.get() == null){
            startTime.set(System.currentTimeMillis());
        }
        System.out.println("方法执行完执行...afterRunning");
        log.info("耗时（毫秒）：" +  (System.currentTimeMillis() - startTime.get()));
        log.info("返回数据：{}", rst);
        log.info("==========================================>");
    }

    @AfterThrowing("within(top.jojoace.CustomAnnotation.todo.Do*)")
    public void afterThrowing(){
        System.out.println("异常出现之后...afterThrowing");
    }

}
